package wang.wangby.lazydoc.model;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import lombok.Data;
import wang.wangby.annotation.Api;
import wang.wangby.annotation.Param;
import wang.wangby.annotation.Remark;
import wang.wangby.annotation.Return;
import wang.wangby.lazydoc.common.DocParameterType;
import wang.wangby.lazydoc.common.DocRules;
import wang.wangby.utils.StringUtil;
import wang.wangby.utils.converter.JsonUtil;

@Data
public class ApiInfo {

	// 接口对应的controller类
	private Class clazz;
	// 接口对应的方法
	private Method method;
	//文档生成规则
	private DocRules docRules;

	
	public ApiInfo(DocRules docRules) {
		this.docRules=docRules;
	}
	
	// 接口名称，默认类名.方法名
	public String getName() {
		return clazz.getSimpleName() + "." + method.getName();
	}

	public String getDescription() {
		Remark rmk = AnnotationUtils.getAnnotation(method, Remark.class);
		if (!StringUtil.isEmpty(rmk)) {
			return rmk.value();
		}
		return method.getName();
	}

	public String getUrl() {
		String parent = "";
		RequestMapping classMapping = AnnotationUtils.getAnnotation(clazz, RequestMapping.class);
		if (classMapping != null && classMapping.value() != null && classMapping.value().length > 0) {
			parent = classMapping.value()[0];
		}
		RequestMapping mp = AnnotationUtils.getAnnotation(method, RequestMapping.class);
		if (mp.value() == null || mp.value().length < 1) {
			Api api=AnnotationUtils.getAnnotation(method, Api.class);
			if(api!=null) {
				return parent + api.path();
			}
			return parent;
		}
		return parent + mp.value()[0];
	}

	private RequestMapping methodMapping() {
		return AnnotationUtils.getAnnotation(method, RequestMapping.class);
	}

	public String getContentType() {
		if (isReturnJson()) {
			return "application/json;charset=UTF-8";
		}
		String[] produces = methodMapping().produces();
		if (produces.length == 0) {
			return "text/html;charset=UTF-8";
		}
		return StringUtil.join(Arrays.asList(produces), t -> t);
	}

	public String getRequestMethod() {
		RequestMethod[] requestMethod = methodMapping().method();
		if (requestMethod == null || requestMethod.length == 0) {
			return "ALL";
		}
		return StringUtil.join(Arrays.asList(requestMethod), t -> t.toString());
	}

	public String getFullName() {
		return clazz.getName() + "." + method.getName();
	}

	// 获得参数信息
	public List<ApiParameter> getParameters() {
		List list = new ArrayList();
		Type[] types = method.getGenericParameterTypes();
		Parameter[] params = method.getParameters();
		Param[] paramAnn = method.getAnnotationsByType(Param.class);
		Map<Parameter, Param> configMap = pair(params, paramAnn);

		for (int i = 0; i < types.length; i++) {
			String name=params[i].getName();
			DocParameterType type=DocParameterType.getType(types[i], types[i]);
			Param config=configMap.get(params[i]);
			ApiParameter pa = new ApiParameter(docRules,type,name,null,config);
			list.add(pa);
		}
		return list;
	}

	/**
	 * 将参数和参数配置信息组合进行匹配 如果个数相等,直接按顺序匹配,否则按paramAnn设置的参数名
	 * 
	 */
	private Map<Parameter, Param> pair(Parameter[] params, Param[] paramAnn) {
		Map<Parameter, Param> map = new HashMap();
		if (params.length == paramAnn.length) {
			for (int i = 0; i < params.length; i++) {
				map.put(params[i], paramAnn[i]);
			}
		} else {
			for (int i = 0; i < params.length; i++) {
				String name = params[i].getName();
				for (int j = 0; j < paramAnn.length; j++) {
					if (name.equalsIgnoreCase(paramAnn[j].name())) {
						map.put(params[i], paramAnn[j]);
						break;
					}
				}
			}
		}
		return map;
	}

	// 调试时输入的参数,复合对象直接用复合对象,数组就复制3份
	public List<InputParam> getDebugParams() {
		List<InputParam> list = new ArrayList();
		for (ApiParameter pa : this.getParameters()) {
			list.addAll(pa.getDebugParams());
		}
		return list;
	}

	public boolean isRequestJson() {
		if (method.getParameters().length == 1) {
			RequestBody reqBody = AnnotationUtils.getAnnotation(method.getParameters()[0], RequestBody.class);
			return reqBody != null;
		}
		return false;
	}

	public boolean isReturnJson() {
		ResponseBody bdoy = AnnotationUtils.getAnnotation(clazz, ResponseBody.class);
		if (bdoy != null) {
			return true;
		}
		return AnnotationUtils.getAnnotation(method, ResponseBody.class) != null;
	}

	public String getJsonParam() {
		if (this.getParameters().size() == 0) {
			return "{}";
		}
		ApiParameter pa = getParameters().get(0);
		Object o=pa.newJsonParam();
		return JsonUtil.NULL.toFormatString(o);
	}

	public ApiResult getResult() {
		Type type=method.getGenericReturnType();
		DocParameterType docType=DocParameterType.getType(type, type);
		ApiResult ret = new ApiResult(this,docType,AnnotationUtils.getAnnotation(method, Return.class));
		return ret;
	}
	

}
